<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>

</body>
<script>
  // 目的 ：改变this指向，让fn的this指向object
  // 怎么能改变this指向？
  // 谁调用指向谁
  // 让object调用fn
  // 给object添加一个fn(func)属性，让object调用fn，这样fn的this就指向object了
  Function.prototype.myCall = function (ctx, ...agrs) {
    // 如果函数的最后一个命名参数以...为前缀，则它将成为一个由剩余参数组成的真数组，其中从0（包括）到theArgs.length（排除）的元素由传递给函数的实际参数提供。
    ctx = (ctx === null || ctx === undefined) ? globalThis : ctx;
    // this就是fn
    const key = Symbol('key');
    ctx[key] = this;
    Object.defineProperty(ctx, key, {
      enumerable: false,
      value: this
    })
    const result = ctx[key](...agrs);
    delete ctx[key];
    return result;
  }
  Function.prototype.myApply = function (ctx, agrs) {
    return Function.prototype.myCall(ctx, ...agrs)
  }
  Function.prototype.myBind = function (ctx, ...external) {
    const that = this;
    return function (...internal) {
      // new.target 属性允许你检测函数或构造方法是否是通过new运算符被调用的。在通过new运算符被初始化的函数或构造方法中，new.target返回一个指向构造方法或函数的引用。在普通的函数调用中，new.target 的值是undefined。
      if (new.target) {
          return new that(...allArgs)
        } else {
          return that.myCall(ctx, ...external, ...internal)
        }

    }
  }
  const object = {
    name: '这是我的名字'
  }
  function fn(a, b) {
    console.log(this.name, a, b)
  }
  fn.myCall(object, 1, 2)
</script>

</html>